package com.speljohan.rsbot.gui;

import static com.speljohan.rsbot.util.GlobalConfiguration.OperatingSystem.WINDOWS;

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import com.speljohan.rsbot.accessors.Client;
import com.speljohan.rsbot.account.Account;
import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.bot.input.CanvasWrapper;
import com.speljohan.rsbot.bot.input.Listener;
import com.speljohan.rsbot.event.EventMulticaster;
import com.speljohan.rsbot.event.impl.CharacterMovedLogger;
import com.speljohan.rsbot.event.impl.DrawBoundaries;
import com.speljohan.rsbot.event.impl.DrawGround;
import com.speljohan.rsbot.event.impl.DrawInventory;
import com.speljohan.rsbot.event.impl.DrawItems;
import com.speljohan.rsbot.event.impl.DrawMouse;
import com.speljohan.rsbot.event.impl.DrawNPCs;
import com.speljohan.rsbot.event.impl.DrawObjects;
import com.speljohan.rsbot.event.impl.DrawPlayers;
import com.speljohan.rsbot.event.impl.DrawSettings;
import com.speljohan.rsbot.event.impl.ServerMessageLogger;
import com.speljohan.rsbot.event.impl.TActualMousePosition;
import com.speljohan.rsbot.event.impl.TAnimation;
import com.speljohan.rsbot.event.impl.TFPS;
import com.speljohan.rsbot.event.impl.TFloorHeight;
import com.speljohan.rsbot.event.impl.TLoginIndex;
import com.speljohan.rsbot.event.impl.TMenuActions;
import com.speljohan.rsbot.event.impl.TMousePosition;
import com.speljohan.rsbot.event.impl.TPlayerPosition;
import com.speljohan.rsbot.event.impl.TUserInputAllowed;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.event.listeners.TextPaintListener;
import com.speljohan.rsbot.script.Methods;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.ScriptHandler;
import com.speljohan.rsbot.util.GlobalConfiguration;
import com.speljohan.rsbot.util.ScreenshotUtil;
import com.speljohan.rsbot.util.logging.TextAreaLogHandler;

public class BotGUI extends JFrame implements ActionListener {
	private static final long serialVersionUID = -4411033752001988794L;
	static {
		// Curse rs's heavyweight
		JPopupMenu.setDefaultLightWeightPopupEnabled(false);
	}

	public static void compile(final boolean scripts) {
		BotGUI.log.info("Compiling " + (scripts ? "scripts" : "bot"));
		final String cmd = "\""
				+ Bot.getWorkDir().getAbsolutePath()
				+ (GlobalConfiguration.isOperatingSystem(WINDOWS) ? "\\Compile.bat\""
						+ (scripts ? " /F" : " /Q")
						: "//compile\"" + (scripts ? " -f" : ""));
		new Thread(new Runnable() {
			public void run() {
				Process p = null;
				BotGUI.log.log(Level.FINE, "Running: " + cmd);
				try {
					p = Runtime.getRuntime().exec(cmd);

					// TODO: Get output stream and print to log

					p.waitFor();
					if (scripts) {
						Bot.getScriptHandler().reloadScripts();
					} else {

						Bot.getScriptHandler().reload();
					}
				} catch (final Exception e) {
					BotGUI.log.log(Level.SEVERE, "Failed to compile", e);
				} finally {
					if (p != null) {
						p.destroy();
					}
				}
			}
		}).start();
	}

	private Bot bot;
	protected Map<String, JCheckBoxMenuItem> commandCheckMap = new HashMap<String, JCheckBoxMenuItem>();

	private final EventMulticaster eventMulticaster = new EventMulticaster();
	protected Map<String, EventListener> listeners = new TreeMap<String, EventListener>();
	private final File menuSetting;
	private JScrollPane textScroll;
	private TrayIcon trayIcon;

	private final HashMap<String, String> themes = new HashMap<String, String>();

	private static final Logger log = Logger.getLogger(BotGUI.class.getName());

	private JButton userInputButton;

	public BotGUI(final String arg) {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (final Exception e) {
		}

		themes.put("System", UIManager.getSystemLookAndFeelClassName());
		themes.put("Metal", UIManager.getCrossPlatformLookAndFeelClassName());
		themes.put("Motif", "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
		themes
				.put("Nimbus",
						"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");

		menuSetting = new File(new File(Bot.getWorkDir(), "Settings"),
				"Debug.txt");

		boolean members = true;

		if (arg.isEmpty()) {
			final String[] options = { "Free", "Members" };
			final int result = JOptionPane.showOptionDialog(null,
					"Please select the type of world to play on.", "Play",
					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
					null, options, options[1]);
			if (result == JOptionPane.CLOSED_OPTION
					|| result == JOptionPane.CANCEL_OPTION) {
				return;
			}
			members = result != 0;
		} else if (arg.equals("nonmember")) {
			members = false;
		}

		// pick initialisation world at random; large sample not required as
		// client re-routes
		// free = odd; members = even
		final int[] prefix = members ? new int[] { 6, 24, 70, 104, 130, 160 }
				: new int[] { 5, 29, 41, 57, 95, 127 };
		final int id = prefix[(int) Math.floor(Math.random() * prefix.length)];
		final String sid = Integer.toString(id);
		initializeGUI(sid);
		BotGUI.log.info("Loaded World " + sid);

		setTitle();
		setLocationRelativeTo(getOwner());
		setIconImage(Toolkit.getDefaultToolkit().getImage(
				GlobalConfiguration.LOGO_PATH));
		setVisible(true);
		bot.startClient();
	}

	public void actionPerformed(final ActionEvent e) {
		final String action = e.getActionCommand();
		final int z = action.indexOf('.');
		final String[] command = new String[2];
		if (z == -1) {
			command[0] = action;
			command[1] = "";
		} else {
			command[0] = action.substring(0, z);
			command[1] = action.substring(z + 1);
		}
		if (command[0].equals("File")) {
			final ScriptHandler sh = Bot.getScriptHandler();
			if ("Run Script".equals(command[1])) {
				showRunScriptSelector();
			} else if ("Stop Script".equals(command[1])) {
				showStopScriptSelector();
			} else if ("Pause/Resume Script".equals(command[1])) {
				final Map<Integer, Script> running = sh.getRunningScripts();
				if (running.size() == 1) {
					final int id = running.keySet().iterator().next();
					int result;
					if (running.get(id).isPaused) {
						result = JOptionPane.showConfirmDialog(this,
								"Would you like to resume the script "
										+ running.get(id).getName() + "?",
								"Resume Script", JOptionPane.OK_CANCEL_OPTION,
								JOptionPane.QUESTION_MESSAGE);
					} else {
						result = JOptionPane.showConfirmDialog(this,
								"Would you like to pause the script "
										+ running.get(id).getName() + "?",
								"Pause Script", JOptionPane.OK_CANCEL_OPTION,
								JOptionPane.QUESTION_MESSAGE);
					}
					if (result == JOptionPane.OK_OPTION) {
						sh.pauseScript(id);
					}
				} else {
					final PauseScriptSelector sss = new PauseScriptSelector(
							this, sh.getRunningScripts());
					if (sss.showToUser()) {
						final int id = sss.getSelectedScript();
						sh.pauseScript(id);
					}
				}
			} else if ("Block User Input".equals(command[1])) {
				Listener.blocked = !Listener.blocked;
				final int height = userInputButton.getIcon().getIconHeight();
				userInputButton.setIcon(new SimpleIcon(height, height,
						Listener.blocked ? Color.red : Color.green, null));
			} else if ("Save Screenshot".equals(command[1])) {
				ScreenshotUtil.takeScreenshot(new Methods().isLoggedIn());
			} else if ("Select Randoms".equals(command[1])) {
				new RandomSelector(this, sh.getRandoms()).setVisible(true);
			} else if ("Select AntiBans".equals(command[1])) {
				new AntiBanSelector(this, sh.getAntiBan()).setVisible(true);
			}
		} else if (command[0].equals("Edit")) {
			if ("Accounts".equals(command[1])) {
				final AccountManager am = new AccountManager(this, bot
						.getAccountHandler());
				am.setVisible(true);
			} else if ("Use Less CPU".equals(command[1])) {
				CanvasWrapper.slowGraphics = ((JCheckBoxMenuItem) e.getSource())
						.isSelected();
			} else if ("Hide Tray Icon".equals(command[1])) {
				if (SystemTray.getSystemTray().getTrayIcons().length == 0) {
					try {
						SystemTray.getSystemTray().add(trayIcon);
					} catch (final AWTException e1) {
					}
				} else {
					SystemTray.getSystemTray().remove(trayIcon);
				}
			} else if ("Hide Input Button".equals(command[1])) {
				userInputButton.setVisible(!((JCheckBoxMenuItem) e.getSource())
						.isSelected());
			}
		} else if (command[0].equals("Source")) {
			final ScriptHandler sh = Bot.getScriptHandler();
			if ("Compile All".equals(command[1])) {
				BotGUI.compile(false);
			} else if ("Compile Scripts".equals(command[1])) {
				BotGUI.compile(true);
			} else if ("Reload Plugins".equals(command[1])) {
				sh.reload();
			} else if ("Add Script".equals(command[1])) {
				final AddScript addScript = new AddScript(this);
				addScript.pack();
				addScript.setResizable(false);
				addScript.setLocationRelativeTo(this);
				addScript.setVisible(true);
			}
		} else if (command[0].equals("View")) {
			final boolean selected = ((JCheckBoxMenuItem) e.getSource())
					.isSelected();
			if ("All Debugging".equals(command[1])) {
				for (final String key : listeners.keySet()) {
					final EventListener el = listeners.get(key);
					final boolean wasSelected = commandCheckMap.get(key)
							.isSelected();
					commandCheckMap.get(key).setSelected(selected);
					if (selected) {
						if (!wasSelected) {
							eventMulticaster.addListener(el);
						}
					} else {
						if (wasSelected) {
							eventMulticaster.removeListener(el);
						}
					}
				}
				commandCheckMap.get("All Text Debugging").setSelected(selected);
				commandCheckMap.get("All Paint Debugging")
						.setSelected(selected);
			} else if ("Hide Log Window".equals(command[1])) {
				textScroll.setVisible(!selected);
				pack();
			} else if ("All Text Debugging".equals(command[1])) {
				if (!selected) {
					commandCheckMap.get("All Debugging").setSelected(false);
				}
				for (final String key : listeners.keySet()) {
					final EventListener el = listeners.get(key);
					if (el instanceof TextPaintListener) {
						final boolean wasSelected = commandCheckMap.get(key)
								.isSelected();
						commandCheckMap.get(key).setSelected(selected);
						if (selected) {
							if (!wasSelected) {
								eventMulticaster.addListener(el);
							}
						} else {
							if (wasSelected) {
								eventMulticaster.removeListener(el);
							}
						}
					}
				}
			} else if ("All Paint Debugging".equals(command[1])) {
				if (!selected) {
					commandCheckMap.get("All Debugging").setSelected(false);
				}
				for (final String key : listeners.keySet()) {
					final EventListener el = listeners.get(key);
					if (el instanceof PaintListener) {
						final boolean wasSelected = commandCheckMap.get(key)
								.isSelected();
						commandCheckMap.get(key).setSelected(selected);
						if (selected) {
							if (!wasSelected) {
								eventMulticaster.addListener(el);
							}
						} else {
							if (wasSelected) {
								eventMulticaster.removeListener(el);
							}
						}
					}
				}
			} else {
				final EventListener el = listeners.get(command[1]);
				commandCheckMap.get(command[1]).setSelected(selected);
				if (selected) {
					eventMulticaster.addListener(el);
				} else {
					commandCheckMap.get("All Text Debugging")
							.setSelected(false);
					commandCheckMap.get("All Paint Debugging").setSelected(
							false);
					commandCheckMap.get("All Debugging").setSelected(false);
					eventMulticaster.removeListener(el);
				}
			}
		} else if (command[0].equals("Theme")) {
			setTheme(command[1]);
		} else if (command[0].equals("Help")) {
			if ("Forums".equals(command[1])) {
				openURL("http://www.rsbot.org/vb/");
			} else if ("Troubleshooting".equals(command[1])) {
				openURL("http://code.google.com/p/rsbotsvn/w/list");
			} else if ("About".equals(command[1])) {
				JOptionPane
						.showMessageDialog(
								this,
								new String[] {
										"An open source modified game client.",
										"Written by Speljohan, Qauters and ins3 with thanks to other contributors.",
										"Visit http://www.rsbot.org/ for more information." },
								"About", JOptionPane.INFORMATION_MESSAGE);
			}
		} else if ("User Input".equals(command[0])) {
			commandCheckMap.get("Block User Input").doClick();
		}
	}

	private JMenuBar constructMenu() {
		final List<String> debugItems = new ArrayList<String>();
		debugItems.add("All Debugging");
		debugItems.add("Hide Log Window");
		debugItems.add("-");
		debugItems.add("All Paint Debugging");
		for (final String key : listeners.keySet()) {
			final EventListener el = listeners.get(key);
			if (el instanceof PaintListener) {
				debugItems.add(key);
			}
		}
		debugItems.add("-");
		debugItems.add("All Text Debugging");
		for (final String key : listeners.keySet()) {
			final EventListener el = listeners.get(key);
			if (el instanceof TextPaintListener) {
				debugItems.add(key);
			}
		}
		debugItems.add("-");
		for (final String key : listeners.keySet()) {
			final EventListener el = listeners.get(key);
			if (!(el instanceof TextPaintListener)
					&& !(el instanceof PaintListener)) {
				debugItems.add(key);
			}
		}
		for (final ListIterator<String> it = debugItems.listIterator(); it
				.hasNext();) {
			final String s = it.next();
			if (s.equals("-")) {
				continue;
			}
			it.set("ToggleF " + s);
		}

		final String[] themeSet = new String[themes.size()];
		int themeIndex = 0;
		for (final String key : themes.keySet()) {
			themeSet[themeIndex] = "Toggle"
					+ (key.equals("System") ? "T" : "F") + " " + key;
			themeIndex++;
		}

		final String[] titles = new String[] { "File", "Edit", "Source",
				"View", "Theme", "Help" };
		final String[][] elements = new String[][] {
				{ "Run Script", "Stop Script", "Pause/Resume Script", "-",
						"ToggleF Block User Input", "Save Screenshot", "-",
						"Select Randoms", "Select AntiBans" },
				{ "Accounts", "-", "ToggleF Use Less CPU",
						"ToggleF Hide Tray Icon", "ToggleF Hide Input Button" },
				{ "Add Script", "-", "Compile All", "Compile Scripts", "-",
						"Reload Plugins" },
				debugItems.toArray(new String[debugItems.size()]), themeSet,
				{ "Forums", "Troubleshooting", "-", "About" } };
		final JMenuBar bar = new JMenuBar();
		for (int i = 0; i < titles.length; i++) {
			final String title = titles[i];
			final JMenu menu = new JMenu(title);
			final String[] elems = elements[i];
			for (String e : elems) {
				if (e.equals("-")) {
					menu.add(new JSeparator());
				} else {
					JMenuItem jmi;
					if (e.startsWith("Toggle")) {
						e = e.substring("Toggle".length());
						final char state = e.charAt(0);
						e = e.substring(2);
						jmi = new JCheckBoxMenuItem(e);
						if (state == 't' || state == 'T') {
							jmi.setSelected(true);
						}
						commandCheckMap.put(e, (JCheckBoxMenuItem) jmi);
					} else {
						jmi = new JMenuItem(e);
					}
					jmi.addActionListener(this);
					jmi.setActionCommand(title + "." + e);
					menu.add(jmi);
				}
			}
			bar.add(menu);
		}
		return bar;
	}

	private void initializeGUI(final String world) {
		final File cwd = new File(".");
		bot = new Bot(cwd, world);

		Bot.getEventManager().getMulticaster().addListener(eventMulticaster);
		Listener.blocked = false;
		registerListeners();

		//setResizable(false);
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

		addWindowListener(new WindowAdapter() {
			public void windowClosing(final WindowEvent e) {
				if (safeClose()) {
					dispose();
					shutdown();
				}
			}
		});

		final JMenuBar bar = constructMenu();
		setJMenuBar(bar);

		final int iconHeight = GlobalConfiguration.isOperatingSystem(WINDOWS) ? bar
				.getPreferredSize().height / 2
				: 10;

		userInputButton = new JButton("User Input", new SimpleIcon(iconHeight,
				iconHeight, Color.green, null));

		userInputButton.addActionListener(this);
		userInputButton.setFocusable(false);

		final JToolBar toolBar = new JToolBar();

		if (GlobalConfiguration.isOperatingSystem(WINDOWS)) {
			bar.add(Box.createHorizontalGlue());
			bar.add(userInputButton);
		} else if (!GlobalConfiguration.isOperatingSystem(WINDOWS)) {
			toolBar.addComponentListener(new ComponentListener() {
				public void componentHidden(final ComponentEvent e) {
				}

				public void componentMoved(final ComponentEvent e) {
				}

				public void componentResized(final ComponentEvent e) {
					pack();
				}

				public void componentShown(final ComponentEvent e) {
				}
			});

			final JButton startScriptButton = new JButton("Run Script");
			startScriptButton.addActionListener(new ActionListener() {
				public void actionPerformed(final ActionEvent e) {
					showRunScriptSelector();
				}
			});
			final JButton pauseResumeButton = new JButton("Pause"); /*
																	 * TODO: Use
																	 * JToggleButton
																	 * instead?
																	 */
			pauseResumeButton.addActionListener(new ActionListener() {
				public void actionPerformed(final ActionEvent e) {
					final String command = e.getActionCommand();
					for (final Script script : Bot.getScriptHandler()
							.getRunningScripts().values()) {
						script.isPaused = command.equals("Pause");
					}

					pauseResumeButton
							.setText(command.equals("Pause") ? "Resume"
									: "Pause");
				}
			});
			final JButton stopScriptButton = new JButton("Stop Script");
			stopScriptButton.addActionListener(new ActionListener() {
				public void actionPerformed(final ActionEvent e) {
					showStopScriptSelector();
				}
			});

			toolBar.add(startScriptButton);
			toolBar.add(stopScriptButton);
			toolBar.add(pauseResumeButton);
			toolBar.add(Box.createHorizontalGlue());
			toolBar.add(userInputButton);
		}

		// applet
		final Dimension dim = new Dimension(765, 503);
		final Component loader = bot.getLoader();
		loader.setSize(dim);
		loader.setPreferredSize(dim);
		final JScrollPane appletScroll = new JScrollPane(loader,
				JScrollPane.VERTICAL_SCROLLBAR_NEVER,
				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		appletScroll.setBorder(null);
		appletScroll.getViewport().setSize(dim);
		appletScroll.setPreferredSize(dim);

		// log
		textScroll = new JScrollPane(TextAreaLogHandler.textArea,
				JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		textScroll.setBorder(null);
		textScroll.setPreferredSize(new Dimension(dim.width, 120));
		textScroll.setVisible(true);

		if (!GlobalConfiguration.isOperatingSystem(WINDOWS)) {
			add(toolBar, BorderLayout.NORTH);
		}
		add(appletScroll, BorderLayout.CENTER);
		add(textScroll, BorderLayout.SOUTH);

		pack();
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				trayIcon();
				initListeners();
			}
		});
	}

	protected void initListeners() {
		if (!menuSetting.exists()) {
			try {
				menuSetting.createNewFile();
			} catch (final IOException e) {
				BotGUI.log.warning("Failed to create settings file.");
			}
		} else {
			try {
				final BufferedReader br = new BufferedReader(new FileReader(
						menuSetting));
				String s;
				while ((s = br.readLine()) != null) {
					final JCheckBoxMenuItem item = commandCheckMap.get(s);
					if (item != null) {
						item.doClick();
					}
				}
			} catch (final IOException e) {
				BotGUI.log.warning("Unable to read settings.");
			}
		}

	}

	private boolean isLoggedIn() {
		final Client client = Bot.getClient();
		final int index = client == null ? -1 : client.getLoginIndex();
		return index == 30 || index == 25;
	}

	@SuppressWarnings("unchecked")
	public void openURL(final String url) {
		final String osName = System.getProperty("os.name");
		try {
			if (osName.startsWith("Mac OS")) {
				final Class fileMgr = Class
						.forName("com.apple.eio.FileManager");
				final Method openURL = fileMgr.getDeclaredMethod("openURL",
						new Class[] { String.class });
				openURL.invoke(null, url);
			} else if (osName.startsWith("Windows")) {
				Runtime.getRuntime().exec(
						"rundll32 url.dll,FileProtocolHandler " + url);
			} else { // assume Unix or Linux
				final String[] browsers = { "firefox", "opera", "konqueror",
						"epiphany", "mozilla", "netscape" };
				String browser = null;
				for (int count = 0; count < browsers.length && browser == null; count++) {
					if (Runtime.getRuntime().exec(
							new String[] { "which", browsers[count] })
							.waitFor() == 0) {
						browser = browsers[count];
					}
				}
				if (browser == null) {
					throw new Exception("Could not find web browser");
				} else {
					Runtime.getRuntime().exec(new String[] { browser, url });
				}
			}
		} catch (final Exception e) {
			JOptionPane.showMessageDialog(this, "Error Opening Browser",
					"Error", JOptionPane.ERROR_MESSAGE);
		}
	}

	/**
	 * Registers a listener.
	 * */
	protected void registerListener(final String name, final EventListener el) {
		listeners.put(name, el);
	}

	/**
	 * Registers the default listeners so they can be displayed in the debug
	 * menu.
	 * */
	protected void registerListeners() {
		// Text
		registerListener("Login Index", TLoginIndex.inst);
		registerListener("Animation", TAnimation.inst);
		registerListener("Floor Height", TFloorHeight.inst);
		registerListener("Player Position", TPlayerPosition.inst);
		registerListener("Mouse Position", TMousePosition.inst);
		registerListener("Actual Mouse Position", TActualMousePosition.inst);
		registerListener("User Input Allowed", TUserInputAllowed.inst);
		registerListener("Menu Actions", TMenuActions.inst);
		registerListener("FPS", TFPS.inst);

		// Paint
		registerListener("Players", DrawPlayers.inst);
		registerListener("NPCs", DrawNPCs.inst);
		registerListener("Objects", DrawObjects.inst);
		registerListener("Mouse", DrawMouse.inst);
		registerListener("Inventory", DrawInventory.inst);
		registerListener("Ground", DrawGround.inst);
		registerListener("Items", DrawItems.inst);
		registerListener("Calc Test", DrawBoundaries.inst);
		registerListener("Settings", DrawSettings.inst);

		// Other
		registerListener("Character Moved (LAG)", CharacterMovedLogger.inst);
		registerListener("Server Messages", ServerMessageLogger.inst);
	}

	private boolean safeClose() {
		boolean pass = true;
		if (isLoggedIn()) {
			final int result = JOptionPane.showConfirmDialog(this,
					"Are you sure you would like to quit?", "Close",
					JOptionPane.WARNING_MESSAGE, JOptionPane.YES_NO_OPTION);
			pass = result == JOptionPane.YES_OPTION;
		}
		return pass;
	}

	void setTheme(final String Name) {
		for (final String key : themes.keySet()) {
			final boolean match = key.equals(Name);
			if (match) {
				try {
					UIManager.setLookAndFeel(themes.get(key));
				} catch (final Exception e) {
				}
				SwingUtilities.updateComponentTreeUI(this);
			}
			commandCheckMap.get(key).setSelected(match);
		}
		BotGUI.log.info("Set theme to " + Name);
	}

	private void setTitle() {
		setTitle((Bot.getAccount() == null ? "" : Bot.getAccount()
				.getUsername()
				+ " - ")
				+ "RSBot Beta");
	}

	private void showRunScriptSelector() {
		final ScriptHandler sh = Bot.getScriptHandler();
		final Collection<Account> accounts = bot.getAccountHandler()
				.getAccounts();
		if (accounts.size() == 0) {
			JOptionPane
					.showMessageDialog(this,
							"No accounts found! Please create one before using the bot.");
			final AccountManager am = new AccountManager(this, bot
					.getAccountHandler());
			am.setVisible(true);
		} else {
			final ScriptSelector ss = new ScriptSelector(this, sh.getScripts(),
					accounts);
			if (ss.showToUser()) {
				bot.setAccount(ss.getAccount());
				setTitle();
				sh.runScript(ss.getScript(), ss.getArguments());
				if (!Listener.blocked) {
					commandCheckMap.get("Block User Input").doClick();
				}
			}
		}
	}

	private void showStopScriptSelector() {
		final ScriptHandler sh = Bot.getScriptHandler();
		final Map<Integer, Script> running = sh.getRunningScripts();
		if (running.size() == 1) {
			final int id = running.keySet().iterator().next();
			final int result = JOptionPane.showConfirmDialog(this,
					"Would you like to stop the script "
							+ running.get(id).getName() + "?", "Stop Script",
					JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);

			if (result == JOptionPane.OK_OPTION) {
				sh.stopScript(id);
			}
		} else {
			final StopScriptSelector sss = new StopScriptSelector(this, sh
					.getRunningScripts());
			if (sss.showToUser()) {
				final int id = sss.getSelectedScript();
				sh.stopScript(id);
			}
		}
	}

	private void shutdown() {
		try {
			final BufferedWriter bw = new BufferedWriter(new FileWriter(
					menuSetting));
			boolean f = true;
			for (final JCheckBoxMenuItem item : commandCheckMap.values()) {
				if (item == null) {
					continue;
				}

				if (item.isSelected() && !item.getText().startsWith("All")) {
					if (!f) {
						bw.newLine();
					}
					f = false;

					bw.write(item.getText());
				}
			}
			bw.close();
		} catch (final Exception e) {
			e.printStackTrace();
		}
		BotGUI.log.info("Closing");
		System.exit(0);
	}

	private void trayIcon() {
		if (SystemTray.isSupported()) {

			final SystemTray tray = SystemTray.getSystemTray();
			final Image image = Toolkit.getDefaultToolkit().getImage(
					GlobalConfiguration.LOGO_PATH);

			final ActionListener exitListener = new ActionListener() {
				public void actionPerformed(final ActionEvent e) {
					BotGUI.log.info("Exiting...");
					System.exit(0);
				}
			};

			final ActionListener hideListener = new ActionListener() {
				public void actionPerformed(final ActionEvent e) {
					BotGUI.log.info("Hide taskbar icon");
					setVisible(!isVisible());
				}
			};

			final PopupMenu popup = new PopupMenu();
			final MenuItem exitButton = new MenuItem("Exit");
			exitButton.addActionListener(exitListener);
			final MenuItem hideTaskBarIcon = new MenuItem("Hide from taskbar");
			hideTaskBarIcon.addActionListener(hideListener);

			popup.add(hideTaskBarIcon);
			popup.addSeparator();
			popup.add(exitButton);

			trayIcon = new TrayIcon(image, "RSBot", popup);

			final ActionListener actionListener = new ActionListener() {
				public void actionPerformed(final ActionEvent e) {
					// trayIcon.displayMessage("Action Event",
					// "An Action Event Has Been Performed!",
					// TrayIcon.MessageType.INFO);
					setVisible(!isVisible());
				}
			};

			trayIcon.setImageAutoSize(true);
			trayIcon.addActionListener(actionListener);

			try {
				tray.add(trayIcon);
			} catch (final Exception e) {
				BotGUI.log.log(Level.WARNING,
						"System tray could not be created.", e);
			}

		} else {
			BotGUI.log.warning("System tray is not supported.");
		}

	}

}
